/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.flexengine.view;

import com.flexengine.component.GameComponent;
import com.flexengine.cursor.GameCursor;
import com.flexengine.engine.Renderable;
import com.flexengine.math.Circle;
import com.flexengine.math.Form2D;
import com.flexengine.math.Form3D;
import com.flexengine.math.Hexagon;
import com.flexengine.math.Triangle;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferStrategy;
import java.text.AttributedCharacterIterator;
import java.util.Map;

/**
 * @author Luann R. Athayde
 * @version 1.0
 * @since 1.0
 */
public class GraphicsJ2D extends Graphics {
    
    private BufferStrategy bStrategy;
    private Graphics2D     graphics;

    private GraphicsJ2D() {
        bStrategy = GameWindow.getInstance().getBufferStrategy();
        if( bStrategy!=null ) {
            graphics = (Graphics2D) bStrategy.getDrawGraphics();
        } else {
            graphics = null;
        }
    }
    private GraphicsJ2D(java.awt.Graphics2D graphics) {
        this.graphics = graphics;
    }
    
    @Override
    public Graphics create() {
        GraphicsJ2D g = new GraphicsJ2D();
        g.graphics = (Graphics2D) graphics.create();
        return g;
    }

    @Override
    public void clear() {
        fillRect(
                0, 0,
                GameWindow.getInstance().getWidth(), 
                GameWindow.getInstance().getHeight());
    }

    @Override
    public void clear(Color color) {
        setColor(color);
        fillRect(
                0, 0,
                GameWindow.getInstance().getWidth(), 
                GameWindow.getInstance().getHeight());
    }
    
    @Override
    public void translate(int x, int y) {
        graphics.translate(x, y);
    }

    @Override
    public Color getColor() {
        return graphics.getColor();
    }

    @Override
    public void setColor(Color c) {
        graphics.setColor(c);
    }

    @Override
    public Font getFont() {
        return graphics.getFont();
    }

    @Override
    public void setFont(Font font) {
        graphics.setFont(font);
    }

    @Override
    public FontMetrics getFontMetrics(Font f) {
        return graphics.getFontMetrics(f);
    }

    @Override
    public Rectangle getClipBounds() {
        return graphics.getClipBounds();
    }

    @Override
    public void clipRect(int x, int y, int width, int height) {
        graphics.clearRect(x, y, width, height);
    }

    @Override
    public void copyArea(int x, int y, int width, int height, int dx, int dy) {
        graphics.copyArea(x, y, width, height, dx, dy);
    }

    @Override
    public void drawLine(int x1, int y1, int x2, int y2) {
        graphics.drawLine(x1, y1, x2, y2);
    }

    @Override
    public void fillRect(int x, int y, int width, int height) {
        graphics.fillRect(x, y, width, height);
    }

    @Override
    public void clearRect(int x, int y, int width, int height) {
        graphics.clearRect(x, y, width, height);
    }

    @Override
    public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
        graphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
    }

    @Override
    public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
        graphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
    }

    @Override
    public void drawOval(int x, int y, int width, int height) {
        graphics.drawOval(x, y, width, height);
    }

    @Override
    public void fillOval(int x, int y, int width, int height) {
        graphics.fillOval(x, y, width, height);
    }

    @Override
    public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
        graphics.drawArc(x, y, width, height, startAngle, arcAngle);
    }

    @Override
    public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
        graphics.fillArc(x, y, width, height, startAngle, arcAngle);
    }

    @Override
    public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
        graphics.drawPolyline(xPoints, yPoints, nPoints);
    }

    @Override
    public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
        graphics.drawPolygon(xPoints, yPoints, nPoints);
    }

    @Override
    public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
        graphics.fillPolygon(xPoints, yPoints, nPoints);
    }

    @Override
    public void drawString(String str, int x, int y) {
        graphics.drawString(str, x, y);
    }

    @Override
    public void drawString(AttributedCharacterIterator iterator, int x, int y) {
        graphics.drawString(iterator, x, y);
    }

    @Override
    public void dispose() {
        graphics.dispose();
    }

    @Override
    public void setComposite(Composite comp) {
        graphics.setComposite(comp);
    }

    @Override
    public void setPaint(Paint paint) {
        graphics.setPaint(paint);
    }

    @Override
    public void setStroke(Stroke s) {
        graphics.setStroke(s);
    }

    @Override
    public void setRenderingHint(Key hintKey, Object hintValue) {
        graphics.setRenderingHint(hintKey, hintValue);
    }

    @Override
    public Object getRenderingHint(Key hintKey) {
        return graphics.getRenderingHint(hintKey);
    }

    @Override
    public void setRenderingHints(Map<?, ?> hints) {
        graphics.setRenderingHints(hints);
    }
    
    @Override
    public void drawRect(int x, int y, int width, int height) {
        graphics.drawRect(x, y, width, height);
    }

    @Override
    public void addRenderingHints(Map<?, ?> hints) {
        graphics.addRenderingHints(hints);
    }

    @Override
    public RenderingHints getRenderingHints() {
        return graphics.getRenderingHints();
    }

    @Override
    public void translate(double tx, double ty) {
        graphics.translate(tx, ty);
    }

    @Override
    public void rotate(double theta) {
        graphics.rotate(theta);
    }

    @Override
    public void rotate(double theta, double x, double y) {
        graphics.rotate(theta, x, y);
    }

    @Override
    public void scale(double sx, double sy) {
        graphics.scale(sx, sy);
    }

    @Override
    public void shear(double shx, double shy) {
        graphics.shear(shx, shy);
    }

    @Override
    public void transform(AffineTransform Tx) {
        graphics.transform(Tx);
    }

    @Override
    public void setTransform(AffineTransform Tx) {
        graphics.setTransform(Tx);
    }

    @Override
    public AffineTransform getTransform() {
        return graphics.getTransform();
    }

    @Override
    public Paint getPaint() {
        return graphics.getPaint();
    }

    @Override
    public Composite getComposite() {
        return graphics.getComposite();
    }

    @Override
    public void setBackground(Color color) {
        graphics.setBackground(color);
    }

    @Override
    public Color getBackground() {
        return graphics.getBackground();
    }

    @Override
    public Stroke getStroke() {
        return graphics.getStroke();
    }

    @Override
    public void clip(Shape s) {
        graphics.clip(s);
    }

    @Override
    public FontRenderContext getFontRenderContext() {
        return graphics.getFontRenderContext();
    }

    @Override
    public void draw(Texture texture, int x, int y) {
        if( texture!=null ) {
            graphics.drawImage(texture.getImage(), x, y, null);
        }
    }
    @Override
    public void draw(GameCursor gCursor) {
        if( gCursor!=null && gCursor.getTexture()!=null && graphics!=null && gCursor.getLocation()!=null ) {
            Image cursorImage = gCursor.getTexture().getImage();
            if( cursorImage!=null ) {
            graphics.drawImage(
                    cursorImage,
                    gCursor.getLocation().x, gCursor.getLocation().y,
                    null);
            }
        }
    }

    @Override
    public void draw(Sprite sprite, int x, int y) {
        
    }

    @Override
    public void draw(GameComponent gameComponent, int x, int y) {
        if( gameComponent != null ) {
            graphics.translate(x, y);
            gameComponent.render(this);
            graphics.translate(0, 0);
        }
    }

    @Override
    public void draw(Renderable obj) {
        draw(obj, 0, 0);
    }
    @Override
    public void draw(Renderable obj, int x, int y) {
        if( obj != null ) {
            graphics.translate(x, y);
            obj.render(this);
            graphics.translate(0, 0);
        }
    }

    @Override
    public void fillPolygon(Polygon polygon) {
        graphics.fillPolygon(polygon);
    }

    @Override
    public void drawPolygon(Polygon polygon) {
        graphics.drawPolygon(polygon);
    }

    @Override
    public void draw(Shape s) {
        graphics.draw(s);
    }

    @Override
    public void draw(Form2D form) {
        if( form instanceof Circle) {
            Circle c = (Circle)form;
            graphics.drawOval((int)c.getX(), (int)c.getY(), (int)c.getDiameter(), (int)c.getDiameter());
        } else if( form instanceof com.flexengine.math.Rectangle ) {
            com.flexengine.math.Rectangle r = (com.flexengine.math.Rectangle)form;
            graphics.drawRect((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
        } else if( form instanceof Triangle ) {
            Triangle t = (Triangle)form;
            graphics.drawPolygon(
                    new int[] {(int)t.getPointA().getX(), (int)t.getPointB().getX(), (int)t.getPointC().getX()},
                    new int[] {(int)t.getPointA().getY(), (int)t.getPointB().getY(), (int)t.getPointC().getY()},
                    3);
        } else if( form instanceof Hexagon ) {
            Hexagon hex = (Hexagon)form;
            int hx[] = hex.getXPoints();
            int hy[] = hex.getYPoints();
            graphics.drawPolygon(hx, hy, 6);
        }
    }

    @Override
    public void draw(Form3D form) {
    }
    
    @Override
    public void fill(Form2D form) {
        if( form instanceof Circle) {
            Circle c = (Circle)form;
            graphics.fillOval((int)c.getX(), (int)c.getY(), (int)c.getDiameter(), (int)c.getDiameter());
        } else if( form instanceof com.flexengine.math.Rectangle ) {
            com.flexengine.math.Rectangle r = (com.flexengine.math.Rectangle)form;
            graphics.fillRect((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
        } else if( form instanceof Triangle ) {
            Triangle t = (Triangle)form;
            graphics.fillPolygon(
                    new int[] {(int)t.getPointA().getX(), (int)t.getPointB().getX(), (int)t.getPointC().getX()},
                    new int[] {(int)t.getPointA().getY(), (int)t.getPointB().getY(), (int)t.getPointC().getY()},
                    3);
        } else if( form instanceof Hexagon ) {
            Hexagon hex = (Hexagon)form;
            int hx[] = hex.getXPoints();
            int hy[] = hex.getYPoints();
            graphics.fillPolygon(hx, hy, 6);
        }
    }

    @Override
    public void fill(Form3D form) {
    }
    
    @Override
    public void update() {
        if( bStrategy != null ) {
            graphics = (Graphics2D)bStrategy.getDrawGraphics();
        }
    }

    public BufferStrategy getBufferStrategy() {
        return bStrategy;
    }

    public void setBufferStrategy(BufferStrategy bStrategy) {
        if( bStrategy!=null ) {
            this.bStrategy = bStrategy;
        }
    }
    
    @Override
    public String toString() {
        return "GraphicsJ2D - graphics = "+graphics;
    }
    
    public static GraphicsJ2D newInstance(BufferStrategy bStrategy) {
        GraphicsJ2D g = new GraphicsJ2D();
        g.bStrategy = bStrategy;
        return g;
    }
    
    private static GraphicsJ2D instance;
    static GraphicsJ2D getInstance() {
        if( instance == null ) {
            instance = new GraphicsJ2D();
        }
        return instance;
    }
    
}
